home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / dlink / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-09  |  19.1 KB  |  788 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6.  
  7. /*
  8.  *  DLINK files options
  9.  *
  10.  *  The first object module is considered to be what is run.  Remaining object
  11.  *  modules are included.  Any files not ending in .o are considered to be
  12.  *  libraries and are resolved at exactly the point they occur on the command line.
  13.  *
  14.  *  For Any option requiring a file argument, that argument may
  15.  *  be placed right next to the option or with an intervening space.  Options
  16.  *  must each have their own '-'.
  17.  *
  18.  *  PC relative accesses beyond 32K cause a jump table to be installed for
  19.  *  said accesses.   DLink cannot current handle jump-table creation
  20.  *  when a given module is larger than 32K Bytes.
  21.  *
  22.  *  DLink currently loads every single file and object module into memory
  23.  *
  24.  *  SECTION ORDERING IS PRESERVED.  Sections of like names are merged
  25.  *  together in the same order they appear on the command line.  Sections
  26.  *  of like name within a given library are merged in no particular order
  27.  *  but are guarenteed to occur after previously specified object files
  28.  *  and libraries and before subsequently specified files.  PC-RELATIVE
  29.  *  jump tables are placed in the same sections that reference them.
  30.  *
  31.  *  Note especially that the above guarentees allow DLink to provide
  32.  *  an autoinit/autoexit section capability (where referencing one
  33.  *  section in a module brings in a differently named section in that
  34.  *  same module which is then coagulated to other sections from other
  35.  *  modules named the same into, finally, a single contiguous section
  36.  *  in the executable.
  37.  *
  38.  *  RESIDENT capabilities.  If -r is specified, DLink allows no
  39.  *  absolute data/bss references except to __DATA_BAS.    Presumably
  40.  *  all such references will use A4-relative addressing.  Additionaly,
  41.  *  DLink assumes a copy of the DATA+BSS space will be allocated by
  42.  *  the startup code so NO BSS SPACE IS ALLOCATED.  If the startup
  43.  *  code attempts to use the (nonexistant) BSS space beyond the static
  44.  *  data it will be referencing unallocated ram.  __RESIDENT is set to 1
  45.  *
  46.  *  If -r is not specified then __RESIDENT is set to 0 and BSS space
  47.  *  will exist beyond the end of data, but will NOT be initialized to 0.
  48.  *
  49.  *  FRAGMENTATION is generally not specified, but will occur anyway for
  50.  *  any segment name beginning with 'far' or with special hunk flags set.
  51.  *
  52.  *  file.o[bj]        an object file
  53.  *  otherfile        a library
  54.  *  @file        a data file containing FILES and LIBRARIES, *no* options
  55.  *            allowed.
  56.  *
  57.  *  -<option>        see switch below
  58.  */
  59.  
  60. /*
  61. **      $Filename: main.c $
  62. **      $Author: dice $
  63. **      $Revision: 30.326 $
  64. **      $Date: 1995/12/24 06:10:39 $
  65. **      $Log: main.c,v $
  66.  * Revision 30.326  1995/12/24  06:10:39  dice
  67.  * .
  68.  *
  69.  * Revision 30.157  1995/01/11  13:20:42  dice
  70.  * added VDISTRIBUTION .. prints registered, commercial, or minidice in help
  71.  *
  72.  * Revision 30.5  1994/06/13  18:38:36  dice
  73.  * removed assignment prefix to include for unix portability
  74.  *
  75.  * Revision 30.0  1994/06/10  18:05:39  dice
  76.  * .
  77.  *
  78. **/
  79.  
  80.  
  81. #include "defs.h"
  82. #include "DLink_rev.h"
  83.  
  84. static char *DCopyright =
  85. "Copyright (c) 1992,1993,1994 Obvious Implementations Corp., Redistribution & Use under DICE-LICENSE.TXT." VERSTAG;
  86.  
  87.  
  88. Prototype char *OutName;
  89. Prototype short FragOpt;
  90. Prototype short SymOpt;
  91. Prototype short ResOpt;
  92. Prototype short PIOpt;
  93. Prototype short DDebug;
  94. Prototype short ExitCode;
  95. Prototype short AbsWordOpt;
  96. Prototype short VerboseOpt;
  97. Prototype short ChipOpt;
  98. Prototype short DebugOpt;
  99. Prototype short ErrorOpt;
  100. Prototype FILE    *ErrorFi;
  101. Prototype long    WordBaseAddr;
  102. Prototype short NumExtHunks;
  103. Prototype char    PostFix[64];
  104.  
  105. Prototype char Tmp[256];
  106.  
  107. Prototype List FList;
  108. Prototype List MList;
  109. Prototype List LList;
  110. Prototype List HList;
  111. Prototype List LibDirList;
  112. Prototype List FileList;
  113.  
  114. Prototype Sym *BssLenSym;
  115. Prototype Sym *DataBasSym;
  116. Prototype Sym *AbsoluteBasSym;
  117. Prototype Sym *DataLenSym;
  118. Prototype Sym *IsResSym;
  119.  
  120. Prototype int main(int, char **);
  121. Prototype void help(void);
  122. Prototype void AddFile(List *, char *);
  123. Prototype void xexit(int);
  124.  
  125. char *OutName = "a.out";
  126. short FragOpt;
  127. short SymOpt;
  128. short ResOpt;
  129. short PIOpt;
  130. short DDebug;
  131. short ExitCode;
  132. short AbsWordOpt;
  133. short VerboseOpt;
  134. short ChipOpt;
  135. short NoLibDirsOpt;
  136. short DebugOpt;
  137. short ErrorOpt;
  138. FILE  *ErrorFi;
  139. long  WordBaseAddr;
  140. short NumExtHunks;
  141.  
  142. static FILE *Fo;
  143.  
  144. char Tmp[256];
  145. char PostFix[64];
  146.  
  147. List FList;
  148. List MList;
  149. List LList;
  150. List HList;
  151. List LibDirList;
  152. List FileList;
  153.  
  154. Sym *BssLenSym;
  155. Sym *DataBasSym;
  156. Sym *AbsoluteBasSym;
  157. Sym *DataLenSym;
  158. Sym *IsResSym;
  159.  
  160. char DLib[128];
  161.  
  162. int _DiceCacheEnable = 1;
  163.  
  164. int
  165. main(int ac, char **av)
  166. {
  167.     short i;
  168.  
  169.     NewList(&FList);    /*  files/libraries in link           */
  170.     NewList(&MList);    /*  modules in final executable        */
  171.     NewList(&LList);    /*  temporary list of modules in a library */
  172.     NewList(&HList);
  173.     NewList(&LibDirList);
  174.     NewList(&FileList);
  175.  
  176.     AddTail(&LibDirList, MakeNode(""));
  177.  
  178.     /*
  179.      * Find prefix
  180.      */
  181.  
  182.     {
  183.     char *ptr;
  184.     char *p2;
  185.  
  186.     if ((ptr = strrchr(av[0], '/')) || (ptr = strrchr(av[0], ':')))
  187.         ++ptr;
  188.     else
  189.         ptr = av[0];
  190.  
  191.     if ((p2 = strchr(ptr, '_')) == NULL)
  192.         p2 = ptr;
  193.     else
  194.         ++p2;
  195.  
  196. #ifdef AMIGA
  197.     sprintf(DLib, "%.*sdlib:", p2 - ptr, ptr);
  198. #else
  199.     sprintf(DLib, "/home/dice/%.*sdlib/", p2 - ptr, ptr);
  200. #endif
  201.     }
  202.  
  203.     SanityCheck(-1);
  204.  
  205.     if (ac == 1)
  206.     help();
  207.  
  208.     for (i = 1; i < ac; ++i) {
  209.     char *ptr = av[i];
  210.     if (*ptr == '-') {
  211.         ptr += 2;
  212.         switch(ptr[-1]) {
  213.         case 'E':
  214.         ErrorOpt = 1;
  215.         if (*ptr == 'E')
  216.             ErrorOpt = 2;
  217.         ptr = av[++i];
  218.         ErrorFi = fopen(ptr, "a");
  219.         break;
  220.         case 'v':
  221.         VerboseOpt = 1;
  222.         break;
  223.         case 'P':
  224.         strcpy(PostFix, ptr);
  225.         break;
  226.         case 'p':
  227.         switch(*ptr) {
  228.         case 'i':
  229.             if (ResOpt)
  230.             puts("Warning, -pi -r = -pr");
  231.             PIOpt = 1;
  232.             break;
  233.         case 'r':
  234.             PIOpt = 1;
  235.             ResOpt = 1;
  236.             break;
  237.         }
  238.         break;
  239.         case 'c':           /*  -chip               */
  240.         if (strncmp(ptr, "hip", 3) == 0)
  241.             ChipOpt = 1;
  242.         else
  243.             help();
  244.         break;
  245.         case 'o':           /*  -o[ ]outputname     */
  246.         OutName = (*ptr) ? ptr : av[++i];
  247.         break;
  248.         case 'f':           /*  -f      (allow fragmentation)   */
  249.         if (ResOpt)
  250.             cerror(EERROR_CANT_FRAG_RES);
  251.         else
  252.             FragOpt = 1;
  253.         break;
  254.         case 's':           /*  -s      (include symbols)       */
  255.         SymOpt = 1;
  256.         break;
  257.         case 'r':           /*  -r      (see comment at top)    */
  258.         if (FragOpt)
  259.             cerror(EERROR_CANT_FRAG_RES);
  260. #ifdef NOTDEF
  261.         if (PIOpt && ResOpt == 0)
  262.             ;
  263.             /*puts("Warning, -pi -r = -pr");*/
  264. #endif
  265.  
  266.         ResOpt = 1;
  267.         FragOpt = 0;
  268.         break;
  269.         case 'm':
  270.         if (*ptr == 'w' || *ptr == 'a') {
  271.             char *dummy;
  272.  
  273.             AbsWordOpt = 1;
  274.             ++ptr;
  275.             if (*ptr == 0)
  276.             ptr = av[++i];
  277.             WordBaseAddr = strtol(ptr, &dummy, 0);
  278.         }
  279.         break;
  280.         case 'd':           /*  -d[#]   (debug hunks)           */
  281.         if (*ptr)
  282.             DebugOpt = strtol(ptr, NULL, 0);
  283.         else
  284.             DebugOpt = 1;
  285.         break;
  286.         case 'Z':
  287.         if (*ptr)
  288.             DDebug = atoi(ptr);
  289.         else
  290.             DDebug = 1;
  291.         break;
  292.         case 'L':           /*  -Ldir   search directory        */
  293.         if (strcmp(ptr, "0") == 0) {
  294.             NoLibDirsOpt = 1;
  295.             NewList(&LibDirList);
  296.             AddTail(&LibDirList, MakeNode(""));
  297.         } else {
  298.             Node *node;
  299.             short len;
  300.  
  301.             if (*ptr == 0)
  302.             ptr = av[++i];
  303.             len = strlen(ptr) - 1;
  304.             if (ptr[len] == '/' || ptr[len] == ':')
  305.             node = MakeNode(ptr);
  306.             else
  307.             node = MakeNode2(ptr, "/");
  308.             AddTail(&LibDirList, node);
  309.         }
  310.         break;
  311.         default:
  312.         cerror(EERROR_BAD_OPTION, ptr - 2);
  313.         help();
  314.         }
  315.         continue;
  316.     }
  317.     if (*ptr == '@') {
  318.         FILE *fi = fopen(ptr + 1, "r");
  319.         short j;
  320.         short c;
  321.  
  322.         if (fi == NULL) {
  323.         cerror(EERROR_CANT_OPEN_FILE, ptr + 1);
  324.         help();
  325.         }
  326.         c = getc(fi);
  327.         while (c != EOF) {
  328.         while (c == ' ' || c == 9 || c == '\n')
  329.             c = getc(fi);
  330.         j = 0;
  331.         while (c != ' ' && c != 9 && c != '\n' && c != EOF) {
  332.             Tmp[j++] = c;
  333.             c = getc(fi);
  334.         }
  335.         Tmp[j] = 0;
  336. #ifdef LATTICE            /*    workaround bug in Lattice V5.04    */
  337.         ftell(fi);
  338. #endif
  339.         if (j)
  340.             AddTail(&FileList, MakeNode(Tmp));
  341.         }
  342.         fclose(fi);
  343.         continue;
  344.     }
  345.     AddTail(&FileList, MakeNode(ptr));
  346.     }
  347.     if (i > ac) {
  348.     puts("expected file argument");
  349.     exit(20);
  350.     }
  351.     if (NoLibDirsOpt == 0)
  352.     AddTail(&LibDirList, MakeNode(DLib));
  353.     {
  354.     Node *node;
  355.     while ((node = RemHead(&FileList)) != NULL) {
  356.         AddFile(&FList, node->ln_Name);
  357.         free(node);
  358.     }
  359.     }
  360.     if (PIOpt) {
  361.     if (AbsWordOpt) {
  362.         puts("Cannot have both -pi and -mw");
  363.         exit(20);
  364.     }
  365.     if (FragOpt) {
  366.         puts("Warning: -frag does not work with -pi");
  367.         FragOpt = 0;
  368.     }
  369.     }
  370.  
  371.     /*
  372.      *    Create default symbols
  373.      */
  374.  
  375.     BssLenSym  = CreateSymbol("__BSS_LEN\0\0\0" , 3, NULL, 0, 2);
  376.     DataBasSym = CreateSymbol("__DATA_BAS\0\0\0", 3, NULL, 0, 2);
  377.     DataLenSym = CreateSymbol("__DATA_LEN\0\0\0", 3, NULL, 0, 2);
  378.     IsResSym   = CreateSymbol("__RESIDENT\0\0\0", 3, NULL, 0, 2);
  379.  
  380.     if (ResOpt == 0 || AbsWordOpt || PIOpt)
  381.     AbsoluteBasSym = CreateSymbol("__ABSOLUTE_BAS\0\0", 4, NULL, WordBaseAddr, 2);
  382.  
  383.     SanityCheck(0);
  384.  
  385.     /*
  386.      *    Create module list from file nodes.  Counts the number of hunks in
  387.      *    each module and generally fills out Module(s) and Hunk(s) structures.
  388.      *
  389.      *    When a library is found, all modules in the library are added to their
  390.      *    own separate list then the library is scanned with appropriate modules
  391.      *    transfered to the master list and symbol ref table created for said.
  392.      *
  393.      *    Generates symbol reference table as a side effect.  Duplicate
  394.      *    definitions from different file nodes are reported.
  395.      */
  396.  
  397.     {
  398.     FileNode *fn;
  399.  
  400.     for (fn = GetHead(&FList); fn; fn = GetSucc(&fn->Node)) {
  401.         List *list = (fn->Node.ln_Type == NT_FTOBJ) ? &MList : &LList;
  402.  
  403.         dbprintf(0, ("File %s\n", fn->Node.ln_Name));
  404.  
  405.         while ((char *)fn->DPtr < (char *)fn->Data + fn->Bytes) {
  406.         Module *module;
  407.  
  408.         if ((module = CreateModule(fn)) != NULL) {
  409. #ifdef DEBUG
  410.             if ((DDebug && list == &MList) || DDebug > 4)
  411.             printf(" %s %s, %d hunks %s\n", ((list == &MList) ? "Mod" : "Lib"), module->FNode->Node.ln_Name, module->NumHunks, module->Node.ln_Name);
  412. #endif
  413.             if (list == &MList)
  414.             CreateSymbolTable(module);
  415.             AddTail(list, &module->Node);
  416.         } else {
  417.             printf("Bad hunk in %-15s $%08lx at offset $%08lx\n", fn->Node.ln_Name, *fn->DPtr, (unsigned long)((char *)fn->DPtr - (char *)fn->Data));
  418.             break;
  419.         }
  420.         }
  421.  
  422.         /*
  423.          *    If a library scan library modules for inclusion
  424.          */
  425.  
  426.         if (list == &LList) {
  427.         long numUndef;        /*  non-zero dummy value */
  428.  
  429.         do {
  430.             Module *mod;
  431.             Module *nextMod;
  432.  
  433.             numUndef = 0;
  434.             dbprintf(0, ("Scan Lib\n"));
  435.             for (mod = GetHead(&LList); mod; mod = nextMod) {
  436.             nextMod = GetSucc(&mod->Node);
  437.             if (ScanLibForInclusion(mod)) {
  438.                 dbprintf(0, (" Include %s : %s\n", mod->FNode->Node.ln_Name, mod->Node.ln_Name));
  439.                 numUndef += CreateSymbolTable(mod);
  440.                 dbprintf(0, (" -- End Include --\n"));
  441.                 Remove(&mod->Node);
  442.                 AddTail(&MList, &mod->Node);
  443.             }
  444.             }
  445.         } while (numUndef);
  446.  
  447.         /*
  448.          *  clear out unused modules by putting them on the free list
  449.          */
  450.         {
  451.             Module *mod;
  452.             short i;
  453.  
  454.             while ((mod = RemHead(&LList)) != NULL) {
  455.             for (i = 0; i < mod->NumHunks; ++i)
  456.                 zfree(mod->Hunks[i], sizeof(Hunk));
  457.             if (mod->NumHunks)
  458.                 zfree(mod->Hunks, sizeof(Hunk *) * mod->NumHunks);
  459.             while (mod->ModEnd - mod->ModBeg >= ALIGN(sizeof(Hunk))) {
  460.                 zfree(mod->ModBeg, sizeof(Hunk));
  461.                 ++MemNumHunksMalReclaim;
  462.                 mod->ModBeg += ALIGN(sizeof(Hunk));
  463.             }
  464.             while (mod->ModEnd - mod->ModBeg >= ALIGN(sizeof(Sym))) {
  465.                 zfree(mod->ModBeg, sizeof(Sym));
  466.                 ++MemNumSymsMalReclaim;
  467.                 mod->ModBeg += ALIGN(sizeof(Sym));
  468.             }
  469.             zfree(mod, sizeof(Module));
  470.             }
  471.         }
  472.         }
  473.     }
  474.     }
  475.  
  476.     SanityCheck(1);
  477.  
  478.     /*
  479.      *    Scan modules that will be part of executable and create HunkListNodes
  480.      *    on the HunkList.    (combine hunks together)
  481.      *
  482.      *    This also makes the linker variables more usable by assigning
  483.      *    them to appropriate hunklistnodes.
  484.      */
  485.  
  486.     {
  487.     Module *mod;
  488.     for (mod = GetHead(&MList); mod; mod = GetSucc(&mod->Node))
  489.         CreateHunkListNodes(mod, &HList);
  490.     }
  491.  
  492.     SanityCheck(2);
  493.  
  494.     FinalCombineHunkListNodes(&HList);
  495.  
  496.     /*
  497.      *    Scan hunks for unresolved COMMON symbols, resolve them into their
  498.      *    BSS hunk as appropriate
  499.      */
  500.  
  501.     {
  502.     HunkListNode *hn;
  503.     HunkListNode *nextHn;
  504.  
  505.     for (hn = GetHead(&HList); hn; hn = nextHn) {
  506.         Hunk *hunk;
  507.  
  508.         nextHn = GetSucc(&hn->Node);
  509.         for (hunk = GetHead(&hn->HunkList); hunk; hunk = GetSucc(&hunk->Node))
  510.         ScanHunkExt(hunk, SCAN_COMMON_RESOLVE);
  511.     }
  512.     }
  513.  
  514.     /*
  515.      *    Delete empty hunk list nodes and number non-empty ones.
  516.      *
  517.      *    Generate a base Offset for each hunk.  This is repeated until
  518.      *    HandleJumpTable() tells us we are ok.  HandleJumpTable() checks
  519.      *    all external-label PC-rel-16 relocations.
  520.      *
  521.      *    hn->AddSize specifies bytes allocated beyond any real data, usually
  522.      *    for BSS space that is tagged onto a DATA hunk.    The HF_DATABSS flag
  523.      *    indicates this.
  524.      */
  525.  
  526.     SanityCheck(3);
  527.  
  528.     do {
  529.     HunkListNode *hn;
  530.     HunkListNode *nextHn;
  531.     short hunkNo = 0;
  532.  
  533.     for (hn = GetHead(&HList); hn; hn = nextHn) {
  534.         nextHn = GetSucc(&hn->Node);
  535.  
  536.         hn->FinalSize = 0;
  537.         hn->AddSize = 0;
  538.         {
  539.         Hunk *hunk;
  540.         for (hunk = GetHead(&hn->HunkList); hunk; hunk = GetSucc(&hunk->Node)) {
  541.             hunk->Offset = hn->FinalSize + hn->AddSize;
  542.             if (hunk->Flags & HF_DATABSS) {
  543.             hn->AddSize += (hunk->TotalBytes + 3) & ~3;
  544.             } else {
  545.             if (hn->AddSize)
  546.                 cerror(EERROR_253, hn->AddSize);
  547.             hn->FinalSize += (hunk->TotalBytes + 3) & ~3;
  548.             }
  549.         }
  550.         }
  551.         if (hn->FinalSize + hn->AddSize == 0 && hn->FinalExtDefs == 0) {
  552.         Remove(&hn->Node);
  553.         } else {
  554.         hn->FinalHunkNo = hunkNo++;
  555.         }
  556.     }
  557.     NumExtHunks = hunkNo;
  558.     } while (HandleJumpTable(&HList));
  559.  
  560.     SanityCheck(4);
  561.  
  562.     /*
  563.      *    Resident option.  Put static data into the code segment and
  564.      *    create additional BSS space.  Redirect references to static
  565.      *    data to references to BSS space.
  566.      */
  567.  
  568.     FixInternalSymbols(&HList);
  569.  
  570.     SanityCheck(5);
  571.  
  572.     /*
  573.      *    allocate memory for ExtReloc for each combined hunk, count the amount
  574.      *    of relocation information for each reference index (include any
  575.      *    incidental Reloc32's in the hunks), then copy the appropriate
  576.      *    information taking into account the newly assigned hunk offsets.
  577.      *
  578.      *    There is a ExtReloc32 for each 'final' hunk.  This ExtReloc32 holds
  579.      *    relocation information from this 'final' hunk to other 'final' hunks
  580.      *    in the system and is indexed by final hunk number.
  581.      */
  582.  
  583.     {
  584.     HunkListNode *hn;
  585.     Hunk *hunk;
  586.  
  587.     for (hn = GetHead(&HList); hn; hn = GetSucc(&hn->Node)) {
  588.         hn->ExtReloc32 = zalloc(sizeof(ulong *) * NumExtHunks);
  589.         hn->CntReloc32 = zalloc(sizeof(ulong) * NumExtHunks);
  590.         hn->CpyReloc32 = zalloc(sizeof(ulong) * NumExtHunks);
  591.  
  592.         for (hunk = GetHead(&hn->HunkList); hunk; hunk = GetSucc(&hunk->Node)) {
  593.         /*
  594.          *  scan hunk->Reloc32 and add # of relocations to hn->Cnt*
  595.          */
  596.  
  597.         ScanHunkReloc32(hunk, 0);
  598.  
  599.         /*
  600.          *  relocate 8 and 16 bit references.
  601.          */
  602.  
  603.         ScanHunkReloc8(hunk);
  604.         ScanHunkReloc16(hunk);
  605.         ScanHunkRelocD16(hunk);
  606.  
  607.         /*
  608.          *  scan hunk->Ext symbols and take into account imported
  609.          *  references.  Only 32 bit references are counted for the
  610.          *  final relocation.
  611.          */
  612.  
  613.         ScanHunkExt(hunk, SCAN_RELOC_CNT);
  614.         }
  615.  
  616.         /*
  617.          *    allocate final relocation arrays according to accumulated
  618.          *    statistics above.  Note that CntReloc32[] entries can be 0
  619.          *    indicating no relocation info to that hunk.
  620.          */
  621.  
  622.         {
  623.         short i;
  624.         for (i = 0; i < NumExtHunks; ++i)
  625.             hn->ExtReloc32[i] = zalloc(sizeof(ulong) * hn->CntReloc32[i]);
  626.         }
  627.     }
  628.     }
  629.  
  630.     SanityCheck(6);
  631.  
  632.     /*
  633.      *    Final relocation pass.    Copy appropriate relocation information and
  634.      *    update Data or Code destinations (for 32 bit relocations referencing
  635.      *    hunks with non-zero offsets)
  636.      */
  637.  
  638.     {
  639.     HunkListNode *hn;
  640.     Hunk *hunk;
  641.  
  642.     for (hn = GetHead(&HList); hn; hn = GetSucc(&hn->Node)) {
  643.         dbprintf(0, ("Final file %s\n", hn->Node.ln_Name));
  644.  
  645.         for (hunk = GetHead(&hn->HunkList); hunk; hunk = GetSucc(&hunk->Node)) {
  646.         /*
  647.          *  copy relocation info to the appropriate place in the
  648.          *  final relocation array and make appropriate modifications
  649.          *  for references to hunks with non-zero offsets.
  650.          */
  651.  
  652.         dbprintf(0, (" HUNK %s\n", HunkToStr(hunk)));
  653.  
  654.         SanityCheck(16);
  655.         ScanHunkReloc32(hunk, 1);
  656.         SanityCheck(17);
  657.  
  658.         /*
  659.          *  Copy relocation info for external 32 bit references and
  660.          *  make appropriate modifications for references to hunks
  661.          *  with non-zero offsets.
  662.          *
  663.          *  Also performs 8 and 16 bit relocations.
  664.          */
  665.  
  666.         SanityCheck(18);
  667.         ScanHunkExt(hunk, SCAN_RELOC_RUN);
  668.         SanityCheck(19);
  669.         }
  670.     }
  671.     }
  672.  
  673.     SanityCheck(7);
  674.  
  675.     /*
  676.      *    PIOpt option, combine DATA & BSS into single CODE hunk
  677.      */
  678.  
  679.     if (PIOpt)
  680.     PIOptCombineIntoCode(&HList);
  681.  
  682.     /*
  683.      *    Generate final executable
  684.      */
  685.  
  686.     {
  687.     FILE *fo = fopen(OutName, "w");
  688.  
  689.     if (fo) {
  690.         Fo = fo;
  691.         GenerateFinalExecutable(fo, &HList);
  692.         fclose(fo);
  693. #ifdef AMIGA
  694.         if (ResOpt)
  695.         SetProtection(OutName, 0x00000020);    /*  set Pure and Exec*/
  696.         else
  697.         SetProtection(OutName, 0x00000000);    /*  ensure E bit set */
  698. #endif
  699.     } else {
  700.         cerror(EERROR_CANT_CREATE_FILE, OutName);
  701.     }
  702.     }
  703.  
  704.     SanityCheck(8);
  705.  
  706.     if (VerboseOpt) {
  707.     printf("Memory: %ld+%ld allocated (%ld req %ld recl)\n",
  708.         MemMalloced, MemAllocated, MemRequested, MemReclaimed
  709.     );
  710.     printf("\t%ld symbols %ld hunks %ld modules (%ld,%ld,%ld)\n",
  711.         MemNumSyms, MemNumHunks, MemNumModules,
  712.         MemNumSyms * sizeof(Sym),
  713.         MemNumHunks* sizeof(Hunk),
  714.         MemNumModules * sizeof(Module)
  715.     );
  716.     printf("\t%ld hunks %ld syms reclaimed from body\n",
  717.         MemNumHunksMalReclaim,
  718.         MemNumSymsMalReclaim
  719.     );
  720.     }
  721.     xexit(0);
  722.     return(0); /* not reached */
  723. }
  724.  
  725. void
  726. help()
  727. {
  728.     printf("%s\n%s\n", VSTRING VDISTRIBUTION, DCopyright);
  729.     puts("dlink [files/libs/@files] -o outname -r -s -v <other-options>");
  730.     exit(5);
  731. }
  732.  
  733. void
  734. AddFile(list, name)
  735. List *list;
  736. char *name;
  737. {
  738.     FileNode *fn = zalloc(sizeof(FileNode) + strlen(name) + 1);
  739.     int fd;
  740.  
  741.     fn->Node.ln_Name = (char *)(fn + 1);
  742.     strcpy(fn->Node.ln_Name, name);
  743.  
  744.     fd = open_lpath(name, O_RDONLY | O_BINARY);
  745.     if (fd < 0)
  746.     return;
  747.  
  748.     if ((fn->Bytes = lseek(fd, 0L, 2)) > 0) {
  749.     MemMalloced += fn->Bytes;
  750.     fn->Data = malloc(fn->Bytes);
  751.     fn->DPtr = fn->Data;
  752.     if (fn->Data == NULL)
  753.         NoMemory();
  754.     lseek(fd, 0L, 0);
  755.     if (read(fd, fn->Data, fn->Bytes) != fn->Bytes)
  756.         cerror(EFATAL_ERROR_READING_FILE, name);
  757.     {
  758.         char *str;
  759.         for (str = name + strlen(name); str >= name && *str != '.'; --str);
  760.         if (str >= name && *str == '.' && (str[1] == 'o' || str[1] == 'O')) {
  761.         fn->Node.ln_Type = NT_FTOBJ;
  762.         fn->Node.ln_Pri = 32;
  763.         } else {
  764.         fn->Node.ln_Type = NT_FTLIB;
  765.         fn->Node.ln_Pri = 32;
  766.         }
  767.     }
  768.     dbprintf(0, ("load %-15s %d %ld\n", fn->Node.ln_Name, fn->Node.ln_Type, fn->Bytes));
  769.     Enqueue(list, &fn->Node);
  770.     }
  771.     close(fd);
  772. }
  773.  
  774. void
  775. xexit(code)
  776. int code;
  777. {
  778.     if (ExitCode < code)
  779.     ExitCode = code;
  780.     if (ExitCode > 5) {
  781.     if (Fo)
  782.         fclose(Fo);
  783.     remove(OutName);
  784.     }
  785.     exit(ExitCode);
  786. }
  787.  
  788.